#pragma once
#include <iostream>
#include <string>
#include <functional>
#include <unordered_map>
#include "TcpServer.hpp"
#include "Socket.hpp"
#include "HttpProtocol.hpp"
using namespace SocketModule;
using namespace TcpServerModule;

using http_handler_t = std::function<void(HttpRequest &, HttpResponse &)>; // 输入是Request，输出是Response，通过Request，形成一个Response
class HttpServer
{
public:
    HttpServer(int port)
        : _tsvr(std::make_unique<TcpServer>(port))
    {
    }
    void Register(std::string funcname, http_handler_t func)
    {
        _route[funcname] = func;
    }
    bool SafeCheck(const std::string &service)
    {
        auto iter = _route.find(service);
        return iter != _route.end();
    }
    void Start()
    {
        _tsvr->InitServer([this](SockPtr sockfd, InetAddr client)
                          { return this->HandlerHttpRequest(sockfd, client); });
        _tsvr->Loop();
    }
    std::string ProveCookieWrrite()
    {
        return "Set-Cookie: username=zhangsan;";
    }
    std::string ProveCookieTimeOut()
    {
        return "Set-Cookie: username=zhangsan; Expires=" + ExpireTimeUseRfc1123(60) + ";";
    }
    std::string ProveOtherCookie()
    {
        return "Set-Cookie: password=123456;";
    }
    std::string GetMonthName(int month)
    {
        std::vector<std::string> months = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
        return months[month];
    }
    std::string GetWeekName(int day)
    {
        std::vector<std::string> weeks = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
        return weeks[day];
    }
    std::string ExpireTimeUseRfc1123(int t) // 秒级别的未来UTC时间
    {
        time_t timeout = time(nullptr) + t;
        struct tm *tm = gmtime(&timeout);
        char time_str[64];
        snprintf(time_str, sizeof(time_str), "%s, %02d %s %d %02d:%02d:%02d UTC",
                 GetWeekName(tm->tm_wday).c_str(),
                 tm->tm_mday,
                 GetMonthName(tm->tm_mon).c_str(),
                 tm->tm_year + 1900,
                 tm->tm_hour,
                 tm->tm_min,
                 tm->tm_sec);
        return time_str;
    }
    std::string ProvePath()
    {
        return "Set-Cookie: username=zhangsan; path=/love.html;";
    }
    // 就是我们处理http的入口
    bool HandlerHttpRequest(SockPtr sockfd, InetAddr client)
    {
        LOG(LogLevel::DEBUG) << "HttpServer: get a new client: " << sockfd->Fd() << " addr info: " << client.Addr();
        std::string http_request;
        sockfd->Recv(&http_request); // 在HTTP这里，我们不做报文完整性的处理
        HttpRequest req;
        req.Deserialize(http_request);
        HttpResponse resp;
        // 请求应该被分为两类：1，请求一般的静态资源 2，提交参数，携带参数，需要我们进行交互设置
        if (req.IsHasArgs())
        {
            // 处理参数交互
            if (SafeCheck(req.Path()))
                _route[req.Path()](req, resp);
            else
                resp.Build(req); // debug
        }
        else
        {
            resp.Build(req);
        }
        // 序列化是统一的
        std::string resp_str;
        // 序列化
        resp.SetCookie(ProveCookieWrrite());
        // resp.SetCookie(ProveCookieTimeOut());
        // resp.SetCookie(ProvePath());
        resp.SetCookie(ProveOtherCookie());
        resp.Serialize(&resp_str);
        sockfd->Send(resp_str);
        return true;

        // std::cout << http_request << std::endl; //字节流的请求
        // //  读取请求，对请求进行分析处理 --> 文本处理！
        // //  1. 读取请求的完整性 --- 暂时不做
        // //  2. 完整http反序列化，http response序列化...
        // //  demo 1 : 直接返回一个固定的内容
        //  std::string status_line = "HTTP/1.1 200 OK" + Sep + BlankLine;
        // // 直接返回一个html网页
        // std::string body = "";
        // std::string httpresponse = status_line + body;
        // sockfd->Send(httpresponse);
        return true;
    }
    ~HttpServer() {}

private:
    std::unique_ptr<TcpServer> _tsvr;
    std::unordered_map<std::string, http_handler_t> _route; // 功能路由
};